#include "stdafx.h"
#include <stdio.h>
#include "CommonFunc.h"

//---------------------------------------------------------------------------------------
#define COMMONFUNC_VERSION        "1.0.2"
#define COMMONFUNC_VERSION_NUMBER 1000002
COMMONFUNC_API const char* commonfunc_version(void)
{
    return COMMONFUNC_VERSION;
}

COMMONFUNC_API int commonfunc_version_number(void)
{
    return COMMONFUNC_VERSION_NUMBER;
}

//---------------------------------------------------------------------------------------
static char buffer[0x1000] = { 0 };
static wchar_t buffer_w[0x1000] = { 0 };
COMMONFUNC_API void KdPrintA(const char *format, ...)
{
    va_list argptr;

    va_start(argptr, format);
    vsnprintf_s(buffer, sizeof(buffer), format, argptr);
    va_end(argptr);
    OutputDebugStringA(buffer);
}
COMMONFUNC_API void KdPrintW(const wchar_t *format, ...)
{
    va_list argptr;

    va_start(argptr, format);
    _vsnwprintf_s(buffer_w, sizeof(buffer_w), format, argptr);
    va_end(argptr);
    OutputDebugStringW(buffer_w);
}

//---------------------------------------------------------------------------------------
COMMONFUNC_API int AnsiToUnicode(const char *in, int in_len, wchar_t *out, int max_out_len)
{
    assert(in && out);
    return MultiByteToWideChar(CP_ACP, 0, in, in_len, out, max_out_len);
}

COMMONFUNC_API int UnicodeToAnsi(const wchar_t *in, int in_len, char *out, int max_out_len)
{
    assert(in && out);
    return WideCharToMultiByte(CP_ACP, 0, in, in_len, out, max_out_len, NULL, NULL);
}

//---------------------------------------------------------------------------------------
COMMONFUNC_API int
Array2String(const void *array, int len, char *destStr, int maxLen,
             int num_in_each_line, char *split, char *addon)
{
    assert(array);

    int i, idx = 0;

    maxLen -= 3;
    const unsigned char *charArray = (const unsigned char *)array;
    for (i = 0; i < len && idx < maxLen; i++)
    {
        if (i > 0 && i % num_in_each_line == 0)
        {
            idx += _snprintf(destStr + idx, maxLen - idx, "\n");
        }
        idx += _snprintf(destStr + idx, maxLen - idx + 2, "%02X%s", charArray[i], split);
    }
    idx += _snprintf(destStr + idx, maxLen - idx + 2, "%s", addon);
    return i;
}

COMMONFUNC_API void PrintDebugArray(const void *array, int len)
{
    char buf[0x1000 - 27];

    int idx = 0;
    while (idx < len)
    {
        idx += Array2String((char *)array + idx, len - idx, buf, sizeof(buf), 16, " ", "\n");
        OutputDebugStringA(buf);
    }
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API uint32_t CheckSum(const void *in, int len)
{
    uint32_t sum = 0;
    const uint8_t *cIn = (const uint8_t *)in;

    while (len-- > 0)
    {
        sum += cIn[len];
    }
    return sum;
}

COMMONFUNC_API void Reverse(void *in, int len)
{
    int i, j;
    uint8_t *cIn = (uint8_t *)in;

    for (j = 0, i = len - 1; j < i; --i, ++j)
    {
        uint8_t temp = cIn[i];
        cIn[i] = cIn[j];
        cIn[j] = temp;
    }
}

COMMONFUNC_API int split(char *str, char **arr, const char *del)
{
    if (!str) return 0;

    char **src = arr; 

    for (*arr++ = str; *str; str++) {
        if (*str != *del) continue;

        *str = '\0';
        *arr++ = str+1;
    }

    return arr - src;
}
int split_int(char *str, const char *del, int val[], int max_num)
{
    char *s[0x100];
    int n = split(str, s, del);

    n = MIN(n, max_num);
    for (int i = 0; i < n; ++i) {
        val[i] = atoi(s[i]);
    }
    return n;
}
int split_double(char *str, const char *del, double val[], int max_num)
{
    char *s[0x100];
    int n = split(str, s, del);

    n = MIN(n, max_num);
    for (int i = 0; i < n; ++i) {
        val[i] = atof(s[i]);
    }
    return n;
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API uint32_t get_le_val(const uint8_t *p, int bytes)
{
    uint32_t ret = 0;
    while (bytes-- > 0)
    {
        ret <<= 8;
        ret |= *(p + bytes);
    }

    return ret;
}
COMMONFUNC_API uint32_t get_be_val(const uint8_t *p, int bytes)
{
    uint32_t ret = 0;
    while (bytes-- > 0)
    {
        ret <<= 8;
        ret |= *p++;
    }

    return ret;
}

COMMONFUNC_API void put_le_val(uint32_t val, uint8_t *p, int bytes)
{
    while (bytes-- > 0)
    {
        *p++ = val & 0xFF;
        val >>= 8;
    }
}
COMMONFUNC_API void put_be_val(uint32_t val, uint8_t *p, int bytes)
{
    while (bytes-- > 0)
    {
        *(p + bytes) = val & 0xFF;
        val >>= 8;
    }
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API int compare_float(double x1, double x2)
{
    if (x1 - x2 > 0.00001) return 1;
    else if (x1 - x2 < -0.00001) return -1;
    return 0;
}

COMMONFUNC_API double duround(double indata, int precision)
{
    long pre = 1;

    for (int i = 0; i < precision; i++) pre *= 10;

    int ret = compare_float(indata, 0);
    if (ret > 0) return (int)((indata * pre) + 0.5) / (double)pre;
    else if (ret < 0) return (int)((indata * pre) - 0.5) / (double)pre;
    return 0.0;
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API int file_size(const char *file)
{
    FILE *fp = fopen(file, "rb");
    if (!fp) return -1;

    fseek (fp, 0, SEEK_END);
    int sz = ftell (fp);

    fclose(fp);
    return sz;
}
COMMONFUNC_API int file_write(const char *file, int addr, const void *data, int len)
{
    const char *cData = (const char *)data;
    FILE *fp = fopen(file, "wb");
    if (!fp) return -1;

    fseek(fp, addr, SEEK_SET);
    len = fwrite(cData, 1, len, fp);

    fclose(fp);
    return len;
}
COMMONFUNC_API int file_read(const char *file, int addr, void *data, int len)
{
    char *cData = (char *)data;
    FILE *fp = fopen(file, "rb");
    if (!fp) return -1;

    fseek (fp, 0, SEEK_END);
    int sz = ftell (fp);

    fseek(fp, addr, SEEK_SET);
    memset(data, 0, len);
    int ret = fread(cData, 1, min(len, sz), fp);

    fclose(fp);
    return ret;
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API
void get_build_time(const char *date, const char *time, char *out, int max_count)

{
    char mon_s[20];
    static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

    int day, year;
    sscanf(date, "%s %d %d", mon_s, &day, &year);
    int mon = (strstr(month_names, mon_s) - month_names) / 3 + 1;

    int hour, minute, second;
    sscanf(time, "%02d:%02d:%02d", &hour, &minute, &second);

    _snprintf(out, max_count, "%04d%02d%02d%02d%02d%02d", year, mon, day, hour, minute, second);
}

//---------------------------------------------------------------------------------------
COMMONFUNC_API unsigned long
maketime(const unsigned int year0, const unsigned int mon0,
         const unsigned int day, const unsigned int hour,
         const unsigned int min, const unsigned int sec)
{
	unsigned int mon = mon0, year = year0;

	/* 1..12 -> 11,12,1..10 */
	if (0 >= (int) (mon -= 2)) {
		mon += 12;	/* Puts Feb last since it has leap day */
		year -= 1;
	}

	return ((((unsigned long)
		  (year/4 - year/100 + year/400 + 367*mon/12 + day) +
		  year*365 - 719499
	    )*24 + hour /* now have hours */
	  )*60 + min /* now have minutes */
	)*60 + sec; /* finally seconds */
}
//---------------------------------------------------------------------------------------
COMMONFUNC_API int get_hash(const void *in, int len, uint8_t *out)
{
    typedef struct {
        ULONG i[2];
        ULONG buf[4];    
        unsigned char in[64]; 
        unsigned char digest[16];           
    } MD5_CTX;

    typedef void (WINAPI* PMD5Init)(MD5_CTX *);
    typedef void (WINAPI* PMD5Update)(MD5_CTX *, const unsigned char *, unsigned int);
    typedef void (WINAPI* PMD5Final)(MD5_CTX *);

    PMD5Init MD5Init;
    PMD5Update MD5Update;
    PMD5Final MD5Final;
    HINSTANCE hDLL;
    if (!(hDLL = LoadLibraryA("advapi32.dll"))) return -1;

    MD5Init = (PMD5Init)GetProcAddress(hDLL,"MD5Init");
    MD5Update = (PMD5Update)GetProcAddress(hDLL,"MD5Update");
    MD5Final = (PMD5Final)GetProcAddress(hDLL,"MD5Final");

    MD5_CTX ctx;
    MD5Init(&ctx);
    MD5Update(&ctx, (uint8_t*)in, len);
    MD5Final(&ctx);

    FreeLibrary(hDLL);
    memcpy(out, ctx.digest, MD5DIGESTLEN);
    return MD5DIGESTLEN;
}
//---------------------------------------------------------------------------------------
